package com.utilities.IO.fileWriters;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Set;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Element;

import ca.ualberta.stothard.cgview.Cgview;

import com.utilities.UtilMethods;
import com.utilities.IO.FileUtilities;
import com.utilities.dataStructures.Range;
import com.utilities.fastaUtilities.FindGenes;
import com.utilities.fastaUtilities.OtherUtilities;
import com.utilities.parsers.coordsParser.ParseCoordsFileParser;
import com.utilities.visualiser.PrepareXMLFile;

public class Test {

	private static PrepareXMLFile prepareXMLFile = null;
	private static String[] colors = {"maroon","red","blue","green","orange", "purple","fuchsia","navy",
		"lime","olive","yellow","teal","aqua","silver","gray","white","black"};
	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception 
	{
//		ArrayList<Range> list0 = new ArrayList<Range>();
//		BufferedReader bufferedReader = new BufferedReader(new FileReader("C:/Users/bansalp/Desktop/contig00139Hitx.txt"));
//		String readLine = bufferedReader.readLine();
//		while(readLine != null)
//		{
//			if (!readLine.startsWith("#"))
//			{
//				String[] params = readLine.split("\t");
//				if (params[2].trim().equalsIgnoreCase("100.00") &&
//						(Integer.parseInt(params[4].trim()) == 1 || Integer.parseInt(params[4].trim()) == 0) && 
//						(Integer.parseInt(params[4].trim()) == 1 || Integer.parseInt(params[4].trim()) == 0))
//				{
//					int start = Integer.parseInt(params[8].trim());
//					int end = Integer.parseInt(params[9].trim());
//					if (start > end)
//					{
//						int temp = start; start = end ; end = temp;
//					}
//					String name = params[0];
//					Range range = new Range(start, end, name);
//					list0.add(range);
//				}	
//			}
//			readLine = bufferedReader.readLine();
//		}
//		Collections.sort(list0,new RangeComparator());
//		WriteToFile(list0, "C:/Users/bansalp/Desktop/orderedHits_139.txt");
		
		int seqLength = 4639675;
		ArrayList<Range> list0 = new ArrayList<Range>();
		ArrayList<Range> contigs = new ArrayList<Range>();
		BufferedReader bufferedReader = new BufferedReader(new FileReader("C:/Users/bansalp/Desktop/tiling"));
		String readLine = bufferedReader.readLine();
		int current = 1;
		while(readLine != null)
		{
			if (!readLine.startsWith(">"))
			{
				String[] params = readLine.split("\t");
				int start = Integer.parseInt(params[0]);
				int end = Integer.parseInt(params[1]);
				Range contig = new Range(start, end, params[7].trim());
				contigs.add(contig);
				if (current < start)
				{
					Range range = new Range(current, start - 1, params[7].trim());
					list0.add(range);
					current = end + 1;
				}
				else if (current > start && current < end)
				{
					current = end + 1;
				}
				else if (current > end)
				{
					
				}
			}
			readLine = bufferedReader.readLine();
		}
		if (current < seqLength) 
		{
			Range range = new Range(current, seqLength, "trailing");
			list0.add(range);
		}
//		Collections.sort(list0,new RangeComparator());
		WriteToFile(list0, "C:/Users/bansalp/Desktop/correctGaps.txt");
		ArrayList<Range> allGenes = readFromFile("C:/Users/bansalp/Desktop/AllGenesPossible.out");
		HashMap<Range, ArrayList<Range>> hashMap = new HashMap<Range, ArrayList<Range>>();
		for (Range range : list0)
		{
			ArrayList<Range> overLap = new ArrayList<Range>();
			for (Range gene : allGenes)
			{
				if (gene.getLowerLimit() > range.getUpperLimit())
				{
					break;
				}
				else
				{
					if (!gene.exclusive(range))
					{
						overLap.add(gene);
					}
				}
			}
			if (overLap.size() > 0) hashMap.put(range, overLap);
		}
		
		PrintWriter pw = new PrintWriter(new FileWriter("C:/Users/bansalp/Desktop/MissingGenes.txt"));
		ArrayList<Range> keySet = new ArrayList<Range>(hashMap.keySet());
		ArrayList<Range> genesFound = new PrepareGFF3().setOutputFile("C:/Users/bansalp/Desktop/resultGff3")
		.findRanges();
//		Collections.sort(keySet,new RangeComparator());
		int totalSizeOfGaps = 0;
		for (Range key : keySet)
		{
			ArrayList<Range> list = hashMap.get(key);
			totalSizeOfGaps = totalSizeOfGaps + (key.getUpperLimit() - key.getLowerLimit() + 1);
			for (Range range : list)
			{
				Range found = null;
				for (Range geneFound : genesFound)
				{
					if (geneFound.getMetadata().equalsIgnoreCase(range.getMetadata()))
					{
						found = geneFound; break;
					}
				}
				if (found != null)
				{
					pw.println(key.getLowerLimit() + "\t" +
							   key.getUpperLimit() + "\t" +
							   key.getMetadata() + "\t" +
							   range.getLowerLimit() + "\t" + 
							   range.getUpperLimit() + "\t" + 
							   range.getMetadata() + "\t" +
							   found.getLowerLimit() + "\t" +
							   found.getUpperLimit() + "\t" +
							   found.getMetadata());
							   
				}
				else
				{
					pw.println(key.getLowerLimit() + "\t" +
							   key.getUpperLimit() + "\t" +
							   key.getMetadata() + "\t" +
							   range.getLowerLimit() + "\t" + 
							   range.getUpperLimit() + "\t" + 
							   range.getMetadata());
				}
			}
		}
		pw.flush();
		pw.close();
		System.out.println("Total Gap length is " + totalSizeOfGaps);
		System.out.println("Total number of gaps is " + keySet.size());
		args = new String[3];
		args[0] = "C:/Users/bansalp/Desktop/tiling";
		args[1] = "C:/Users/bansalp/Desktop/scaffoldFile_bak.txt";
		args[2] = "C:/Users/bansalp/Desktop/contigsNotFound2.txt";
		OtherUtilities otherUtilities = new OtherUtilities();
		ArrayList<Range> excludedOnes = findExcludedContigRanges(otherUtilities.reArrangeContigs2(args),
		"C:/Users/bansalp/Desktop/nucmer.coords");
		WriteToFile(excludedOnes, "C:/Users/bansalp/Desktop/excludedData.txt");
		makeVisualisation(list0,seqLength,excludedOnes,contigs);
		
		
//		separateContigsInDifferentFiles();
//		ArrayList<Range> list = new PrepareGFF3().setOutputFile("C:/Users/bansalp/Desktop/resultGff3")
//		.findRanges();
//		int seQlength = list.remove(list.size() - 1).getUpperLimit();
//		Collections.sort(list, new RangeComparator());
//		WriteToFile(list,"C:/Users/bansalp/Desktop/AllGenesFound.out");
//		
//		ArrayList<Range> list2 = new ArrayList<Range>();
//		int currentIndex = 1;
//		for (Range range : list)
//		{
//			int start = range.getLowerLimit();
//			int end = range.getUpperLimit();
//			
//			if (currentIndex < start)
//			{
//				list2.add(new Range(currentIndex, start - 1, range.getMetadata()));
//			}
//			currentIndex = end + 1;
//		}
//		if (currentIndex < seQlength)
//		{
//			list2.add(new Range(currentIndex , seQlength, "end"));
//		}
//		WriteToFile(list2,"C:/Users/bansalp/Desktop/GapsFound.out");
//		RandomAccessFile rand = new RandomAccessFile("C:/Users/bansalp/Desktop/gbkFile2.gbk", "r");
//		String readLine = rand.readLine();
//		FindGenes findGenes = new FindGenes();
//		while(readLine != null)
//		{
//			readLine = readLine.trim();
//			// read only the line that starts with this suffix
//			if (readLine.startsWith("gene  "))
//			{
//				findGenes.makeGeneMap(readLine,rand);
//			}
//			else if (readLine.startsWith("ORIGIN"))
//			{
//				System.out.println("Gene location read. ");
//				break;
//			}
//			readLine = rand.readLine();
//		}
//		rand.close();
//		HashMap<String,ArrayList<String>> hashMap = findGenes.getMap();
//		Set<String> keys = hashMap.keySet();
//		
//		ArrayList<Range> list3 = new ArrayList<Range>();
//		for (String key : keys)
//		{
//			ArrayList<String> positionsInfo = hashMap.get(key);
//			for (String positionInfo : positionsInfo)
//			{
//				String[] params = positionInfo.split("\\.\\.");
//				int start = Integer.parseInt(params[0]);
//				int end = Integer.parseInt(params[1]);
//				if (start > end)
//				{
//					int temp = start; start = end; end = temp;
//				}
//				Range range = new Range(start, end, key);
//				list3.add(range);
//			}
//		}
//		Collections.sort(list3, new RangeComparator());
//		WriteToFile(list3,"C:/Users/bansalp/Desktop/AllGenesPossible.out");
		
//			boolean isClean = isInclean(key,list);
//			if (!isClean)
//			{
//				ArrayList<String> positionsInfo = hashMap.get(key);
//				for (String positionInfo : positionsInfo)
//				{
//					String[] params = positionInfo.split("..");
//					int start = Integer.parseInt(params[0]);
//					int end = Integer.parseInt(params[1]);
//					if (start > end)
//					{
//						int temp = start; start = end; end = temp;
//					}
//					Range range = new Range(start, end, key);
//					ArrayList<Range> isExclusive = isExclusive(range, list2);
//					if (isExclusive != null)
//					{
//						for (Range range2 : isExclusive)
//						{
//							pw.println(range.getLowerLimit() + "\t" + range.getUpperLimit() + "\t"
//									+ range.getMetadata() + "\t" + range2.getLowerLimit() + "\t" + 
//									range2.getUpperLimit());
//						}
//					}
//				}
//			}
//		}
//		pw.flush();
//		pw.close();
//		Collections.sort(list3, new RangeComparator());
	}
	
	private static ArrayList<Range> findExcludedContigRanges(ArrayList<String> list,
			String coordsFile) throws IOException 
	{
		ArrayList<Range> result = new ArrayList<Range>();
		
		BufferedReader bufferedReader = new BufferedReader(new FileReader(coordsFile));
		String readLine = bufferedReader.readLine();
		ParseCoordsFileParser allContigsFileParser = new ParseCoordsFileParser();
		while(readLine != null)
		{
			String[] params = allContigsFileParser.parseCoordsFileLine(readLine);
			if (list.contains(params[14].trim()))
			{
				int start = Integer.parseInt(params[2].trim());
				int end  = Integer.parseInt(params[3].trim());
				if (start > end)
				{
					int temp = start; start = end ; end = start;
				}
				Range range = new Range(start, end, readLine.trim());
				result.add(range);
			}
			readLine = bufferedReader.readLine();
		}
		bufferedReader.close();
		return result;
	}

	private static void makeVisualisation(ArrayList<Range> gaps,int seqLength, ArrayList<Range> excludedOnes,
			ArrayList<Range> contigs) throws ParserConfigurationException
	{
		String[] slots = new String[3];slots[0] = "contigs"; slots[1] = "excludedContigs"; slots[2] = "Gaps";
		initialise(String.valueOf(seqLength),slots);
		makeFeatureSlots(slots.length);
		
		for (Range range : contigs)
		{
			String mouseOver = "Start = " + String.valueOf(range.getLowerLimit())
			+ ", stop = " + String.valueOf(range.getUpperLimit());
			Element feature = prepareXMLFile.createFeature("directStrand0", colors[0], "clockwise-arrow", 
			range.getMetadata(), null,mouseOver,null,null,null);
			prepareXMLFile.createFeatureRange(feature, String.valueOf(range.getLowerLimit()), 
					String.valueOf(range.getUpperLimit()), null);
		}
		
		
		for (Range range : excludedOnes)
		{
			String mouseOver = "Start = " + String.valueOf(range.getLowerLimit())
			+ ", stop = " + String.valueOf(range.getUpperLimit());
			String name = range.getMetadata().split("\t")[14];
			Element feature = prepareXMLFile.createFeature("directStrand1", colors[1], "clockwise-arrow", 
			name.trim(), null,mouseOver,null,null,null);
			prepareXMLFile.createFeatureRange(feature, String.valueOf(range.getLowerLimit()), 
					String.valueOf(range.getUpperLimit()), null);
		}
		
		int i = 0;
		for (Range range : gaps)
		{
			String mouseOver = "Start = " + String.valueOf(range.getLowerLimit())
			+ ", stop = " + String.valueOf(range.getUpperLimit());
			Element feature = prepareXMLFile.createFeature("directStrand2", colors[2], "clockwise-arrow", 
			"gap_"+i, null,mouseOver,null,null,null);
			i++;
			prepareXMLFile.createFeatureRange(feature, String.valueOf(range.getLowerLimit()), 
					String.valueOf(range.getUpperLimit()), null);
		}
		prepareXMLFile.writeToFile("C:/Users/bansalp/Desktop/vXml.xml");
//		String args[] = new String[10];
//		args[0] = "-i";
//		args[1] = "C:/Users/bansalp/Desktop/vXml.xml"; 
//		args[2] = "-e"; 
//		args[3] = "true"; 
//		args[4] = "-s"; 
//		args[5] = "C:/Users/bansalp/Desktop/out";
//		args[6] = "-f"; 
//		args[7] = "png";
//		args[8] = "-x";
//		args[9] = "1,3,6";
//		Cgview.main(args);
	}
	
	private static void initialise(String seqLength, String[] args) throws ParserConfigurationException 
	{
		prepareXMLFile = new PrepareXMLFile().createCGView(seqLength)
		.createLegend("sideLegend", "upper-right", "SanSerif, plain, 10", "0.8");
		
		for (int i = 0; i < args.length; i++)
		{
			String legendLabel = args[i];
			prepareXMLFile = prepareXMLFile.createLegendItem("sideLegend", legendLabel, "SanSerif, plain, 12", true, colors[i]);
		}
		prepareXMLFile = prepareXMLFile.createLegend("lowerleftlegend", "lower-left", "SanSerif, plain, 9", "0.8")
		.createLegendItem("lowerleftlegend", "This map was generated using CGView", null, false, null)
		.createLegend("lowerrightlegend", "lower-right", "SanSerif, plain, 9", "0.8")
		.createLegendItem("lowerrightlegend", "Work done at D-BSSE ETH Zurich", null, false, null);
	}
	
	private static void makeFeatureSlots(int slots) 
	{
		for(int i = 0; i < slots; i++)
		{
			prepareXMLFile = prepareXMLFile.createFeatureSlots("directStrand" + i, "direct",false);
		}
	}

	private static ArrayList<Range> readFromFile(String file) throws Exception
	{
		ArrayList<Range> arrayList = new ArrayList<Range>();
		BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
		String readLine = bufferedReader.readLine();
		while(readLine != null)
		{
			String[] params = readLine.split("\t");
			Range range = new Range(Integer.parseInt(params[0]), 
					Integer.parseInt(params[1]), params[2].trim());
			arrayList.add(range);
			readLine = bufferedReader.readLine();
		}
		return arrayList;
	}
	private static void separateContigsInDifferentFiles() throws Exception
	{
		BufferedReader bufferedReader = new BufferedReader(new FileReader("C:/Users/bansalp/Desktop/scaffoldFile_bak.txt"));
		String readLine = bufferedReader.readLine();
		PrintWriter pw = null;
		while(readLine != null)
		{
			if (readLine.startsWith(">"))
			{
				String params[] = readLine.split(" ");
				String name = params[0].trim().substring(1);
				if (pw != null)
				{
					pw.flush();
					pw.close();
					pw = null;
				}
				pw = new PrintWriter(new FileWriter("C:/Users/bansalp/Desktop/contigs/" + name+".txt"));
			}
			pw.println(readLine);
			readLine = bufferedReader.readLine();
		}
	}

	private static void WriteToFile(ArrayList<Range> list, String fileName) throws IOException {
		PrintWriter pw = new PrintWriter(new FileWriter(fileName));
		for (Range range : list)
		{
			pw.println(range.getLowerLimit() + "\t" + range.getUpperLimit() + "\t" + range.getMetadata());
		}
		pw.flush();
		pw.close();
	}

	private static boolean isInclean(String key, ArrayList<Range> list) 
	{
		for(Range range : list)
		{
			if (key.trim().equalsIgnoreCase(range.getMetadata().trim()));
			return true;
		}
		return false;
	}

	private static ArrayList<Range> isExclusive(Range range, ArrayList<Range> list2) 
	{
		ArrayList<Range> result = new ArrayList<Range>();
		for (Range range2 : list2)
		{
			if (!range.exclusive(range2))
			{
				result.add(range2);
			}
		}
		if (result.size() == 0) return null;
		return result;
	}
}
